package com.meevle.business;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;

import com.meevle.dao.SetDAO;
import com.meevle.dao.SlotCommentDAO;
import com.meevle.dao.SlotDAO;
import com.meevle.dao.UserDAO;
import com.meevle.utilities.HibernateManager;
import com.meevle.utilities.VoToDAoAdapter;
import com.meevle.vo.SetVO;
import com.meevle.vo.SlotCommentVO;
import com.meevle.vo.SlotVO;
import com.meevle.vo.UserVO;

public class PersistenceManagerImpl {

	private static Logger log = Red5LoggerFactory.getLogger(PersistenceManagerImpl.class, "Meevle");
	
	public static void persist(Object object) throws Exception {

		try {
			Session session = HibernateManager.getInstance().getSession();
			session.beginTransaction();
			session.persist(object);
			session.getTransaction().commit();
		} catch (Exception e) {
			throw e;
		}

	}

	public static UserDAO getUser(UserVO userVo) throws Exception
	{
		UserDAO user;
		try {
			Session session = HibernateManager.getInstance().getSession();
			Query query = session.createQuery(
					"from UserDAO user where username = :username").setString(
					"username", userVo.getUsername());

			user = (UserDAO) query.uniqueResult();
		} catch (Exception e) {
			log.error(e.toString());
			throw e;
		} 
		return user;
	}

	public static List<UserDAO> getAllUsers()throws Exception
	{
		List<UserDAO> ret = new ArrayList<UserDAO>();
		try {
			ret = (List<UserDAO>)HibernateManager.getInstance().getSession()
				.createQuery("from UserDAO user")
				.list();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}
		return ret;
	}

	public static void updateUser(UserVO oldVo, UserVO newVo)throws IllegalArgumentException, Exception
	{
		UserDAO old;
		try {
			old = UserDAO.getUser(oldVo);
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
		
		Session session = HibernateManager.getInstance().getSession();
		old.setUsername(newVo.getUsername());
		merge(old, session);
	}

	public static void addSetToUser(UserVO userVo, SetVO projectVo) {
		UserDAO userDao = null;
		SetDAO setDao = null;
		try {
			userDao = UserDAO.getUser(userVo);
			setDao = SetDAO.getSet(projectVo);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			e.printStackTrace();
		}
		if (!userDao.getSets().contains(setDao)) {
			userDao.getSets().add(setDao);
			Session session = HibernateManager.getInstance().getSession();
			merge(userDao, session);
		}

	}

	public static void addTrackToUser(UserVO userVo, SlotVO trackVo)throws IllegalArgumentException, Exception
	{
		UserDAO userDao;
		SlotDAO trackDao;
		try {
			userDao = UserDAO.getUser(userVo);
			trackDao = SlotDAO.getSlot(trackVo);
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
		if (!userDao.getSlots().contains(trackDao)) {
			userDao.getSlots().add(trackDao);
			Session session = HibernateManager.getInstance().getSession();
			merge(userDao, session);
		}
	}
	
	public static void addCommentToUser(UserVO userVo, SlotCommentVO commentVo)throws IllegalArgumentException, Exception
	{
		UserDAO userDao;
		SlotCommentDAO commentDao;
		try {
			userDao = UserDAO.getUser(userVo);
			commentDao = VoToDAoAdapter.getInstance().getSlotCommentDAOFromSlotCommentVO(commentVo, false);
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
		if (!userDao.getSlots().contains(commentDao)) {
			userDao.getComments().add(commentDao);
			Session session = HibernateManager.getInstance().getSession();
			merge(userDao, session);
		}
	}

	public static SlotDAO getSlot(SlotVO trackVo) throws HibernateException {
		SlotDAO track = null;
			try {
				
				track = (SlotDAO)HibernateManager.getInstance().getSession()
					.createQuery("from SlotDAO track where directory = :directory AND slotIndex = :slotIndex")
					.setString("directory", trackVo.getDirectory())
					.setInteger("slotIndex", trackVo.getIndex() )
					.uniqueResult();
			} catch (HibernateException e) {
				log.error(e.getMessage());
				throw e;
			}
		return track;
	}

	public static List<SlotDAO> getAllSlots()throws Exception
	{
		List<SlotDAO> tracks = new ArrayList<SlotDAO>();
		try {
			tracks = (List<SlotDAO>)HibernateManager.getInstance().getSession()
					.createQuery("from SlotDAO t")
					.list();
			
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}
		return tracks;
	}

	public static List<SlotDAO> getAllTracksByName(String trackname)throws Exception
	{
		List<SlotDAO> tracks;
		try {
			tracks = (List<SlotDAO>)HibernateManager.getInstance().getSession()
					.createQuery("from SlotDAO t where name = :name")
					.setParameter("name", trackname)
					.list();
			
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}
		return (tracks==null?new ArrayList<SlotDAO>(0):tracks);
	}
	
	public static void deleteSlot(SlotVO slot) throws Exception
	{
		Session session = HibernateManager.getInstance().getSession();
		SetDAO pr = null;
		try {
			session
					.createQuery("DELETE from SlotDAO where directory = :directory AND slotIndex = :slotIndex")
					.setString("directory", slot.getDirectory())
					.setInteger("slotIndex", slot.getIndex() )
					.executeUpdate();
		
		} catch (HibernateException e) {
			log.error(e.getMessage());
			throw e;
		}
		
	}

	public static SetDAO getSet(SetVO project) throws Exception
	{
		Session session = HibernateManager.getInstance().getSession();
		SetDAO pr = null;
		try {
			pr = (SetDAO)session
					.createQuery("from SetDAO project where name = :name AND owner.username = :username")
					.setString("name", project.getName() )
					.setString("username", project.getOwner().getUsername())
					.uniqueResult();
		} catch (HibernateException e) {
			log.error(e.getMessage());
			throw e;
		}
		return pr;
	}


	public static List<SetDAO> getAllSets()throws Exception
	{
		List<SetDAO> projects;
		try {
			projects = (List<SetDAO>) HibernateManager.getInstance().getSession()
				.createQuery("from SetDAO p")
				.list();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}

		return (projects==null?new ArrayList<SetDAO>(0):projects);
	}

	public static List<SetDAO> getAllProjectsByName(String projectname)throws Exception
	{
		List<SetDAO> projects;
		try {
			projects = (List<SetDAO>)HibernateManager.getInstance().getSession()
				.createQuery("from SetDAO p where name = :name")
					.setParameter("name", projectname)
					.list();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}
		return (projects==null?new ArrayList<SetDAO>(0):projects);
	}
	
	public static List<SetDAO> getAllProjectsByUserName(String username) {
		List<SetDAO> sets;
		try {
			sets = (List<SetDAO>)HibernateManager.getInstance().getSession()
				.createQuery("from SetDAO p where owner.username = :username")
					.setParameter("username", username)
					.list();
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		}
		return (sets==null?new ArrayList<SetDAO>(0):sets);
	}

	/**
	 * Updates a project NOTE: The OWNER will not be updated as this cannot be changed!!!!
	 * @param oldVo
	 * @param newVo
	 * @throws IllegalArgumentException
	 * @throws Exception
	 */
	public static void updateSet(SetVO oldVo, SetVO newVo)throws IllegalArgumentException, Exception
	{
		try {
			SetDAO old = SetDAO.getSet(oldVo);
			Session session = HibernateManager.getInstance().getSession();
			old.setName(newVo.getName());
			merge(old, session);
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}

	}

	/**
	 * Updates a track NOTE: The OWNER, the DIRECTORY, TIMECREATED and the FILENAME will not be updated as this cannot be changed by design desicions!!!!
	 * @param oldVo
	 * @param newVo
	 * @throws IllegalArgumentException
	 * @throws Exception
	 */
	public static void updateTrack(SlotVO oldVo, SlotVO newVo)throws IllegalArgumentException, Exception
	{
		try {
			SlotDAO old = SlotDAO.getSlot(oldVo);

				Session session = HibernateManager.getInstance().getSession();
				old.setName(newVo.getName());
				
				merge(old, session);
		} catch (HibernateException e) {
			e.printStackTrace();
			throw e;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	/**
	 * Merges the object and flushed teh changes to the DB
	 * @param obj
	 * @param session
	 */
	public static void merge(Object obj, Session session)
	{
		session.beginTransaction();
		session.merge(obj);
		session.flush();
		session.getTransaction().commit();
	}
	
	/**
	 * Merges the object and flushed the changes to the DB
	 * @param obj
	 * @param session
	 */
	public static void merge(Object obj)
	{
		Session session = HibernateManager.getInstance().getSession();
		session.beginTransaction();
		session.merge(obj);
		session.flush();
		session.getTransaction().commit();
	}
}